#include "lsp.h"
#include "lspmessage.pb-c.h"
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <errno.h>
#include <strings.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

double epoch_lth = _EPOCH_LTH;
int epoch_cnt = _EPOCH_CNT;
double drop_rate = _DROP_RATE;

/*
 *
 *
 *				LSP RELATED FUNCTIONS
 *
 *
 */  

void lsp_set_epoch_lth(double lth){epoch_lth = lth;}
void lsp_set_epoch_cnt(int cnt){epoch_cnt = cnt;}
void lsp_set_drop_rate(double rate){drop_rate = rate;}


/*
 *
 *
 *				CLIENT RELATED FUNCTIONS
 *
 *
 */  


lsp_client* lsp_client_create(const char* src, int port)
{
	lsp_client *new_lsp = new lsp_client();

	//Get socket file descriptor and save to fd
	struct hostent *server;
	if((new_lsp->sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
	{
		printf("Failed to get Socket FD while creating lsp client.\n");
		delete new_lsp; new_lsp = NULL;
		return NULL;
	}
	
	//Setup connection info for server
	bzero(&(new_lsp->server), sizeof(new_lsp->server));
	new_lsp->server.sin_family = AF_INET;
	new_lsp->server.sin_port = htons(port);
	if(inet_pton(AF_INET, src, &(new_lsp->server)) != 1)
	{
		printf("Failed to convert hostname to IP while creating client.\n");
		delete new_lsp; new_lsp = NULL;
		return NULL;
	}

	//Set socket to non-blocking mode
	if(fcntl(new_lsp->sockfd, F_SETFL, O_NONBLOCK, 1) == -1)
	{
		printf("Failed set socket as non-blocking while creating client.\n");
		delete new_lsp; new_lsp = NULL;
		return NULL;
	}

	//Get connid from server:
	new_lsp->connid = 0;
	new_lsp->seqnum = 0;
	if(!lsp_client_write(new_lsp,NULL,0))
	{
		printf("Failed to send message to server to get connid for new lsp client.\n");
		delete new_lsp; new_lsp = NULL;
		return NULL;
	}
}

int lsp_client_read(lsp_client* a_client, uint8_t* pld)
{
	do{
		char buf[1024];
		sockaddr from;
		socklen_t from_length = sizeof(from);
		int byte_count = recvfrom(a_client->sockfd, buf, sizeof(buf), 0, &from, &from_length);
		
		//If the message does not have atleast a connid and seqid, discard it.
		if(byte_count < 64)
		{
			return 0;
		}
		
		//Extract connid and seqnum from the message.
		unsigned int incoming_connid = 0;
		unsigned int incoming_seqnum = 0;
		memcpy(&incoming_connid, buf, 4);
		memcpy(&incoming_seqnum, buf+4, 4);

		
		if(a_client->connid == 0)
		{
			a_client->connid = incoming_connid;
		}
		
		if(byte_count > 64 && a_client->connid == incoming_connid)
		{
			memcpy(pld, buf+8, byte_count-64);
			return byte_count-64;
		}
	} while(byte_count > 0);
}

bool lsp_client_write(lsp_client* a_client, uint8_t* pld, int lth)
{
	LSPMessage msg = LSPMESSAGE__INIT;
	void* buf;
	unsigned len;
	msg.connid = a_client->connid;
	msg.seqnum = a_client->seqnum;
	msg.payload = {lth,pld};
	//len = lspmessage__get_packed_size(&msg);
	buf = malloc(len);
	//lspmessage__pack(&msg, buf);

	//sendto(a_client->sockfd, buf, len, &(a_client->server), sizeof(a_client->server));
}

bool lsp_client_close(lsp_client* a_client)
{
	
}

/*
 *
 *
 *				SERVER RELATED FUNCTIONS
 *
 *
 */  


lsp_server* lsp_server_create(int port)
{

}

int lsp_server_read(lsp_server* a_srv, void* pld, uint32_t* conn_id)
{

}

bool lsp_server_write(lsp_server* a_srv, void* pld, int lth, uint32_t conn_id)
{

}

bool lsp_server_close(lsp_server* a_srv, uint32_t conn_id)
{

}
